﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cinch;
using System.ComponentModel;
using System.ComponentModel.Composition;

namespace Anata.Client
{
    /// <summary>
    /// Represents a single Image ViewModel
    /// </summary>
    public class TransaksiProdukViewModel : EditableValidatingViewModelBase
    {
        #region Data

        private ViewMode currentViewMode = ViewMode.AddMode;

        #region Data.Primitives
        private DataWrapper<Int32> idTransaksiProduk;
        private DataWrapper<Int32?> idTransaksi;
        private DataWrapper<Int32?> idJenisStok;
        private String namaJenisStok;
        private DataWrapper<Int32?> idKaryawan;
        private String namaKaryawan;
        private DataWrapper<Int32> jumlahProduk;
        private DataWrapper<Int32> hargaProduk;
        private DataWrapper<Int32> potonganHarga;
        private DataWrapper<Int32> komisiKaryawan;
        private DataWrapper<DateTime?> waktuBatal;
        private DataWrapper<Boolean> isBatal;



        private bool isBusy = false;
        private int previousStatusTransaksiProduk;
        #endregion

        private IEnumerable<DataWrapperBase> cachedListOfDataWrappers;

        #region Data.Rules
        private static SimpleRule idKaryawanRule;
        private static SimpleRule idJenisStokRule;
        #endregion

        #region Data.VMs
        #endregion

        #region Data.Services
        private IMessageBoxService messageBoxService;
        private IUIVisualizerService uiVisualizerService;
        private IReferenceProvider referenceProvider;
        #endregion

        #endregion

        #region Constructor
        [ImportingConstructor]
        public TransaksiProdukViewModel(
            IMessageBoxService messageBoxService,
            IUIVisualizerService uiVisualizerService,
            IReferenceProvider referenceProvider)
        {
            #region Constructor.SetupServices
            this.messageBoxService = messageBoxService;
            this.uiVisualizerService = uiVisualizerService;
            this.referenceProvider = referenceProvider;
            this.referenceProvider = referenceProvider;
            #endregion

            #region Constructor.SetupCommands
            ProdukCabangSelectCommand = new SimpleCommand<Object, Object>(CanExecuteProdukCabangSelectCommand, ExecuteProdukCabangSelectCommand);
            KaryawanSelectCommand = new SimpleCommand<Object, Object>(CanExecuteKaryawanSelectCommand, ExecuteKaryawanSelectCommand);
            TransaksiProdukCancelCommand = new SimpleCommand<Object, Object>(CanExecuteTransaksiProdukCancelCommand, ExecuteTransaksiProdukCancelCommand);
            //PromoSelectCommand = new SimpleCommand<Object, Object>(CanExecutePromoSelectCommand, ExecutePromoSelectCommand);
            //FreeGiftSelectCommand = new SimpleCommand<Object, Object>(CanExecuteFreeGiftSelectCommand, ExecuteFreeGiftSelectCommand);
            #endregion

            #region Constructor.CreateDataWrappers
            IdTransaksiProduk = new DataWrapper<Int32>(this, idTransaksiProdukChangeArgs);
            IdTransaksiProduk.IsEditable = true;
            IdTransaksi = new DataWrapper<Int32?>(this, idTransaksiChangeArgs);
            IdTransaksi.IsEditable = true;
            IdJenisStok = new DataWrapper<Int32?>(this, idJenisStokChangeArgs);
            IdJenisStok.IsEditable = true;
            //NamaJenisStok = new DataWrapper<String>(this, namaJenisStokChangeArgs);
            //NamaJenisStok.IsEditable = true;
            IdKaryawan = new DataWrapper<Int32?>(this, idKaryawanChangeArgs);
            IdKaryawan.IsEditable = true;
            //NamaKaryawan = new DataWrapper<String>(this, namaKaryawanChangeArgs);
            //NamaKaryawan.IsEditable = true;
            JumlahProduk = new DataWrapper<Int32>(this, jumlahProdukChangeArgs, JumlahProdukChangeCallback);
            JumlahProduk.IsEditable = true;
            HargaProduk = new DataWrapper<Int32>(this, hargaProdukChangeArgs, HargaProdukChangeCallback);
            HargaProduk.IsEditable = true;
            PotonganHarga = new DataWrapper<Int32>(this, potonganHargaChangeArgs, PotonganHargaChangeCallback);
            PotonganHarga.IsEditable = true;
            KomisiKaryawan = new DataWrapper<Int32>(this, komisiKaryawanChangeArgs);
            KomisiKaryawan.IsEditable = true;
            WaktuBatal = new DataWrapper<DateTime?>(this, waktuBatalChangeArgs);
            WaktuBatal.IsEditable = true;
            IsBatal = new DataWrapper<Boolean>(this, isBatalChangeArgs, IsBatalChangeCallback);
            IsBatal.IsEditable = true;
            IsBatal.DataValue = false;
            #endregion

            //fetch list of all DataWrappers, so they can be used again later without the
            //need for reflection
            cachedListOfDataWrappers =
                DataWrapperHelper.GetWrapperProperties<TransaksiProdukViewModel>(this);

            #region Create Validation Rules
            idKaryawan.AddRule(idKaryawanRule);
            idJenisStok.AddRule(idJenisStokRule);
            #endregion

            #region Constructor.SetupCollections
             #endregion
        }
        #endregion

        #region Static
        static TransaksiProdukViewModel()
        {
            idKaryawanRule = new SimpleRule("DataValue", "IdKaryawan tidak valid",
                (Object domainObject) =>
                {
                    DataWrapper<Int32?> obj = (DataWrapper<Int32?>)domainObject;
                    return obj.DataValue == 0;
                });
            idJenisStokRule = new SimpleRule("DataValue", "IdJenisStok tidak valid",
                (Object domainObject) =>
                {
                    DataWrapper<Int32?> obj = (DataWrapper<Int32?>)domainObject;
                    return obj.DataValue == 0;
                });
        }

        public static int STATUS_TRANSAKSIPRODUK_OK = 0;
        public static int STATUS_TRANSAKSIPRODUK_CANCELLED = 99;
        #endregion

        #region Public Properties

        #region Public.Commands
        public SimpleCommand<Object, Object> ProdukCabangSelectCommand { get; private set; }
        public SimpleCommand<Object, Object> KaryawanSelectCommand { get; private set; }
        public SimpleCommand<Object, Object> TransaksiProdukCancelCommand { get; private set; }
        //public SimpleCommand<Object, Object> PromoSelectCommand { get; private set; }
        //public SimpleCommand<Object, Object> FreeGiftSelectCommand { get; private set; }
        #endregion

        #region Public.ViewMode
        /// <summary>
        /// The current ViewMode, when changed will loop
        /// through all nested DataWrapper objects and change
        /// their state also
        /// </summary>

        static PropertyChangedEventArgs currentViewModeChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.CurrentViewMode);

        public ViewMode CurrentViewMode
        {
            get { return currentViewMode; }
            set
            {
                currentViewMode = value;

                //Now change all the CachedListOfDataWrappers
                //Which sets all the Cinch.DataWrapper<T>s to the correct IsEditable
                //state based on the new ViewMode applied to the ViewModel
                //we can use the Cinch.DataWrapperHelper class for this
                DataWrapperHelper.SetMode(
                    CachedListOfDataWrappers,
                    currentViewMode);

                switch (currentViewMode)
                {
                    case ViewMode.AddMode:
                        //Quantity.DataValue= 0;
                        this.DisplayName = "Transaksi Baru";
                        break;
                    case ViewMode.EditMode:
                        this.DisplayName = "Ubah Transaksi";
                        JumlahProduk.IsEditable = false;
                        break;
                    case ViewMode.ViewOnlyMode:
                        this.DisplayName = "Lihat Transaksi";
                        break;
                }

                NotifyPropertyChanged(currentViewModeChangeArgs);
            }
        }
        #endregion

        #region Public.Data
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idTransaksiProdukChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.IdTransaksiProduk);
        public DataWrapper<Int32> IdTransaksiProduk
        {
            get { return idTransaksiProduk; }
            set
            {
                idTransaksiProduk = value;
                NotifyPropertyChanged(idTransaksiProdukChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idTransaksiChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.IdTransaksi);
        public DataWrapper<Int32?> IdTransaksi
        {
            get { return idTransaksi; }
            set
            {
                idTransaksi = value;
                NotifyPropertyChanged(idTransaksiChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idJenisStokChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.IdJenisStok);
        public DataWrapper<Int32?> IdJenisStok
        {
            get { return idJenisStok; }
            set
            {
                idJenisStok = value;
                NotifyPropertyChanged(idJenisStokChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs namaJenisStokChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.NamaJenisStok);
        public String NamaJenisStok
        {
            get { return namaJenisStok; }
            set
            {
                namaJenisStok = value;
                NotifyPropertyChanged(namaJenisStokChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs hargaProdukChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.HargaProduk);
        public DataWrapper<Int32> HargaProduk
        {
            get { return hargaProduk; }
            set
            {
                hargaProduk = value;
                NotifyPropertyChanged(hargaProdukChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs jumlahProdukChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.JumlahProduk);
        public DataWrapper<Int32> JumlahProduk
        {
            get { return jumlahProduk; }
            set
            {
                jumlahProduk = value;
                NotifyPropertyChanged(jumlahProdukChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs idKaryawanChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.IdKaryawan);
        public DataWrapper<Int32?> IdKaryawan
        {
            get { return idKaryawan; }
            set
            {
                idKaryawan = value;
                NotifyPropertyChanged(idKaryawanChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs namaKaryawanChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.NamaKaryawan);
        public String NamaKaryawan
        {
            get { return namaKaryawan; }
            set
            {
                namaKaryawan = value;
                NotifyPropertyChanged(namaKaryawanChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs komisiKaryawanChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.KomisiKaryawan);
        public DataWrapper<Int32> KomisiKaryawan
        {
            get { return komisiKaryawan; }
            set
            {
                komisiKaryawan = value;
                NotifyPropertyChanged(komisiKaryawanChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs potonganHargaChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.PotonganHarga);
        public DataWrapper<Int32> PotonganHarga
        {
            get { return potonganHarga; }
            set
            {
                potonganHarga = value;
                NotifyPropertyChanged(potonganHargaChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs isBatalChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.IsBatal);
        public DataWrapper<Boolean> IsBatal
        {
            get { return isBatal; }
            set
            {
                isBatal = value;
                NotifyPropertyChanged(isBatalChangeArgs);
            }
        }
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs waktuBatalChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.WaktuBatal);
        public DataWrapper<DateTime?> WaktuBatal
        {
            get { return waktuBatal; }
            set
            {
                waktuBatal = value;
                NotifyPropertyChanged(waktuBatalChangeArgs);
            }
        }
        #endregion

        #region Public.IsBusy
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs isBusyChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.IsBusy);
        public bool IsBusy
        {
            get { return isBusy; }
            set
            {
                isBusy = value;
                NotifyPropertyChanged(isBusyChangeArgs);
            }
        }

        /// <summary>
        /// </summary>
        public int PreviousStatusTransaksiProduk
        {
            get { return previousStatusTransaksiProduk; }
            set
            {
                previousStatusTransaksiProduk = value;
            }
        }
        #endregion

        #region Public.Cached Collection
        /// <summary>
        /// Returns cached collection of DataWrapperBase
        /// </summary>
        public IEnumerable<DataWrapperBase> CachedListOfDataWrappers
        {
            get { return cachedListOfDataWrappers; }
        }
        #endregion

        #region Public.DataVM
        #endregion

        #region Public.SummaryData
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs subTotalHargaProdukChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.SubTotalHargaProduk);
        public Int32 SubTotalHargaProduk
        {
            get { return JumlahProduk.DataValue * HargaProduk.DataValue; }
        }
        
        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs totalHargaProdukChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.TotalHargaProduk);
        public Int32 TotalHargaProduk
        {
            get { return SubTotalHargaProduk - PotonganHarga.DataValue; }
        }

        /// <summary>
        /// </summary>
        static PropertyChangedEventArgs statusTransaksiProdukChangeArgs =
            ObservableHelper.CreateArgs<TransaksiProdukViewModel>(x => x.StatusTransaksiProduk);
        public int StatusTransaksiProduk
        {
            get
            {
                int retval = 0;
                if (isBatal.DataValue)
                {
                    retval = STATUS_TRANSAKSIPRODUK_CANCELLED;
                }
                else
                {
                    retval = STATUS_TRANSAKSIPRODUK_OK;
                }
                return retval;
            }
        }
        #endregion

        #endregion

        #region Command Handlers
        /// <summary>
        /// </summary>
        private bool CanExecuteProdukCabangSelectCommand(Object args)
        {
            return !isBusy
                && idTransaksiProduk.DataValue == 0
                && CurrentViewMode == ViewMode.AddMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteProdukCabangSelectCommand(Object args)
        {
            CabangProdukSelectViewModel pcsvm = new CabangProdukSelectViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
            bool? result = uiVisualizerService.ShowDialog("CabangProdukSelectPopup", pcsvm);
            if (result.HasValue && result.Value)
            {
                Console.WriteLine("masukkk");
                CabangProdukThumbnailViewModel pctvm = (CabangProdukThumbnailViewModel)
                    pcsvm.CabangProduksCV.CurrentItem;
                this.IdJenisStok.DataValue = pctvm.IdJenisStok;
                this.NamaJenisStok = pctvm.NamaJenisStok;
                this.HargaProduk.DataValue = pctvm.HargaProduk;
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteKaryawanSelectCommand(Object args)
        {
            return !isBusy
                && idTransaksiProduk.DataValue == 0
                && CurrentViewMode == ViewMode.AddMode;
        }

        /// <summary>
        /// </summary>
        private void ExecuteKaryawanSelectCommand(Object args)
        {
            KaryawanSelectViewModel ksvm = new KaryawanSelectViewModel(
                messageBoxService,
                uiVisualizerService,
                referenceProvider);
            ksvm.CriteriaSortIdLayanan = 0;
            ksvm.StartLoading();
            bool? result = uiVisualizerService.ShowDialog("KaryawanSelectPopup", ksvm);
            if (result.HasValue && result.Value)
            {
                Console.WriteLine("masukkk");
                KaryawanThumbnailViewModel ktvm = (KaryawanThumbnailViewModel)
                    ksvm.KaryawansCV.CurrentItem;
                this.IdKaryawan.DataValue = ktvm.IdKaryawan;
                this.NamaKaryawan = ktvm.Nama;
            }
        }

        /// <summary>
        /// </summary>
        private bool CanExecuteTransaksiProdukCancelCommand(Object args)
        {
            return !isBusy
                && previousStatusTransaksiProduk != STATUS_TRANSAKSIPRODUK_CANCELLED
                && CurrentViewMode != ViewMode.ViewOnlyMode;
        }
        /// <summary>
        /// </summary>
        private void ExecuteTransaksiProdukCancelCommand(Object args)
        {
            Mediator.Instance.NotifyColleagues("TryRemoveTransaksiProduk", this);
        }

        #endregion

        #region Change Callbacks
        /// <summary>
        /// </summary>
        private void HargaProdukChangeCallback()
        {
            NotifyPropertyChanged(subTotalHargaProdukChangeArgs);
            NotifyPropertyChanged(totalHargaProdukChangeArgs);
            Mediator.Instance.NotifyColleagues<Boolean>("SummaryChangeMessage", true);
        }
        /// <summary>
        /// </summary>
        private void JumlahProdukChangeCallback()
        {
            NotifyPropertyChanged(subTotalHargaProdukChangeArgs);
            NotifyPropertyChanged(totalHargaProdukChangeArgs);
            Mediator.Instance.NotifyColleagues<Boolean>("SummaryChangeMessage", true);
        }
        /// <summary>
        /// </summary>
        private void PotonganHargaChangeCallback()
        {
            NotifyPropertyChanged(totalHargaProdukChangeArgs);
            Mediator.Instance.NotifyColleagues<Boolean>("SummaryChangeMessage", true);
        }
        /// <summary>
        /// </summary>
        private void IsBatalChangeCallback()
        {
            NotifyPropertyChanged(statusTransaksiProdukChangeArgs);
        }
        #endregion

        #region Private Methods
        #endregion

        #region Overrides
        static PropertyChangedEventArgs isValidChangeArgs =
            ObservableHelper.CreateArgs<TransaksiViewModel>(x => x.IsValid);

        public override bool IsValid
        {
            get
            {
                //return base.IsValid and use DataWrapperHelper, if you are
                //using DataWrappers
                return base.IsValid &&
                    DataWrapperHelper.AllValid(cachedListOfDataWrappers);
            }

        }

        public bool IsDirty
        {
            get
            {
                return DataWrapperHelper2.SomeDirty(cachedListOfDataWrappers);
            }
        }

        public override string ToString()
        {
            return String.Format("TransaksiProdukViewModel {0}", this.idTransaksiProduk);
        }
        #endregion

        #region EditableValidatingViewModelBase overrides
        protected override void OnBeginEdit()
        {
            base.OnBeginEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call BeginEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetBeginEdit(cachedListOfDataWrappers);
        }

        /// <summary>
        /// Override hook which allows us to also put any child 
        /// EditableValidatingViewModelBase objects into the EndEdit state
        /// </summary>
        protected override void OnEndEdit()
        {
            base.OnEndEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call CancelEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetEndEdit(cachedListOfDataWrappers);
        }

        /// <summary>
        /// Override hook which allows us to also put any child 
        /// EditableValidatingViewModelBase objects into the CancelEdit state
        /// </summary>
        protected override void OnCancelEdit()
        {
            base.OnCancelEdit();
            //Now walk the list of properties in the OrderViewModel
            //and call CancelEdit() on all Cinch.DataWrapper<T>s.
            //we can use the Cinch.DataWrapperHelper class for this
            DataWrapperHelper.SetCancelEdit(cachedListOfDataWrappers);
        }
        #endregion
    }
}
